#include <unistd.h>
#include "clientsdatabase.h"
#include "os_dependence.h"



ClientsDataBase::~ClientsDataBase()
{
    waitForEmpty();
}


int ClientsDataBase::registerClientThread(ClientThread *c)
{
    push_back(c);
    return 0; // no error
}



int ClientsDataBase::removeClientThread(ClientThread *c)
{
    erase(c);
    return 0; // no error
}



void ClientsDataBase::push_back(ClientThread *cth)
{
    if(cth->ip().isEmpty())
        QMessageBox::warning(0, "O_o", "Client thread has no ip");

    QMutexLocker locker(&mutex);

    int n;
    if( (n = findClientByIP(cth->ip())) != -1 )
    {
        at(n)->pushBack(cth);
    }
    else {
        _database.push_back(new IpConnection(cth));
    }
}



void ClientsDataBase::erase(ClientThread *cth)
{
    qWarning() << "ClientsDataBase::erase" << cth->ip();
    QMutexLocker locker(&mutex);

    qWarning() << "Mutex unlocked";

    int n;
    if( (n = findThread(cth))  > -1 )
    {
        IpConnection *ic = at(n);

        if(!ic) {
            qWarning() << "erase fail";
            return;
        }

        qWarning() << "1";
        ic->erase(cth);
        if( !ic->size() )
        {
            qWarning() << "3";
            _database.remove(n);

            delete ic;
            qWarning() << "4";
        }
        qWarning() << "5";
    }

    qWarning() << "6";
}



int ClientsDataBase::findThread(ClientThread *cth, bool mutex_lock)
{
    if(mutex_lock)
        mutex.lock();
    size_t sz = _database.size();
    for(size_t i=0; i<sz; ++i)
    {
        for(int t=0; t<_database.at(i)->threads.size(); ++t)
        {
            if(_database.at(i)->threads.at(t) == cth) {
                if(mutex_lock)
                    mutex.unlock();
                return i;
            }
        }
    }

    if(mutex_lock)
        mutex.unlock();

    return 0;
}



int ClientsDataBase::findClientByIP(const QString & ip, bool mutex_lock)
{
    if(mutex_lock)
        mutex.lock();
    for(int i=0; i<_database.size(); ++i)
    {
        if( _database[i]->_ip == ip )
        {
            if(mutex_lock)
                mutex.unlock();
            return i;
        }
    }

    if(mutex_lock)
        mutex.unlock();
    return -1;
}



IpConnection * ClientsDataBase::at(int i, bool mutex_lock)
{
    if(mutex_lock)
        mutex.lock();

    if(_database.size() <= i) {
        if(mutex_lock)
            mutex.unlock();
        return 0;
    }

    IpConnection * c;

    if( i < 0 || i >= _database.size())
        c = 0;
    else
        c = _database[i];

    if(mutex_lock)
        mutex.unlock();
    return c;
}


QList <IpConnection*> ClientsDataBase::clients()
{
    QMutexLocker locker(&mutex);

    QList <IpConnection*> list;

    foreach(IpConnection *cl, _database)
    {
        list << cl;
    }

    return list;
}


QStringList ClientsDataBase::clientsIpList()
{
    QStringList list;

    mutex.lock();

    size_t sz = _database.size();
    for(size_t i=0; i<sz; ++i)
    {
        list << _database.at(i)->_ip;
    }

    mutex.unlock();

    return list;
}


int ClientsDataBase::killClientsByIpList(const QStringList & l, bool wait_for_disconnect, bool force)
{
    int killed = 0;
    foreach(const QString & ip, l)
    {
        mutex.lock();
        int i = findClientByIP(ip, false);
        if(i >= 0)
        {
            IpConnection *ic = at(i, false);

            if(ic)
            {
                if(force)
                    ic->forceAbort(false, true);
                else
                    ic->abort(wait_for_disconnect, true);
                killed++;
            }
        }
        mutex.unlock();

    }
    return killed;
}


void ClientsDataBase::waitForEmpty()
{
    int sz;
    do
    {
        mutex.lock();
        sz = size();
        mutex.unlock();
        QSleep::_usleep(400);
    }while(sz > 1);
}
